package com.ac.utils;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.base.helper.Result;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class XssUtils {

    private XssUtils() {
    }

//    private static final Pattern[] PATTERNS = {
//            // Avoid anything in a <script> type of expression
//            Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
//            // Avoid anything in a src='...' type of expression
//            Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
//            Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
//            // Remove any lonesome </script> tag
//            Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
//            // Avoid anything in a <iframe> type of expression
//            Pattern.compile("<iframe>(.*?)</iframe>", Pattern.CASE_INSENSITIVE),
//            // Remove any lonesome <script ...> tag
//            Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
//            // Remove any lonesome <img ...> tag
//            Pattern.compile("<img(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
//            // Avoid eval(...) expressions
//            Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
//            // Avoid expression(...) expressions
//            Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
//            // Avoid javascript:... expressions
//            Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
//            // Avoid vbscript:... expressions
//            Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
//            // Avoid οnlοad= expressions
//            Pattern.compile("on(load|error|mouseover|submit|reset|focus|click)(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)
//    };

    public static String stripXSS(String value) {
        return stripXSS(null, value);
    }

//    public static String stripXSS(String key, String value) {
//        if (StringUtils.isEmpty(value)) {
//            return value;
//        }
//        value = htmlEncode(value);
//        System.out.println("value = " + value);
//        return value;
//    }

    public static String stripXSS(String key, String value) {
        if (value != null) {
            // 如果是时间格式的字符串，仅过滤其中的数字部分
            if (value.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}")) {
                // 提取数字部分
                String digitsOnly = value.replaceAll("\\D", "");
                // 只对数字部分进行XSS过滤
                value = value.replace(digitsOnly, stripXSS(digitsOnly));
            } else {
                value = value;
//                        .replaceAll("&", "&amp;")
//                        .replaceAll("<", "&lt;")
//                        .replaceAll(">", "&gt;")
//                        .replaceAll("\"", "&quot;")
//                        .replaceAll("'", "&#39;")
//                        .replaceAll("\\(", "&#40;")
//                        .replaceAll("\\)", "&#41;")
//                        .replaceAll("eval\\((.*)\\)", "")
//                        .replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
                // 过滤空格
//                value = value.replaceAll("\\s", "");
            }
        }
        return value;
    }

    private static String htmlEncode(char c) {

        switch(c) {

            case '&':

                return "&amp;";

            case '<':

                return "&lt;";

            case '>':

                return "&gt;";

            case '"':

                return "&quot;";

            case ' ':

                return "&nbsp;";

            default:

                return c + "";

        }

    }

    /** 对传入的字符串str进行Html encode转换 */
    public static String htmlEncode(String str) {
        if (str ==null || str.trim().equals(""))   return str;

        StringBuilder encodeStrBuilder = new StringBuilder();
        for (int i = 0, len = str.length(); i < len; i++) {
            encodeStrBuilder.append(htmlEncode(str.charAt(i)));
        }
        return encodeStrBuilder.toString();
    }

    // 该方法包含两个重载方法，第一个方法用来处理整个Result对象，
    // 第二个方法用来处理单个对象中的属性。如果数据是集合类型，先将集合中的对象逐一处理，否则直接处理数据对象本身。
    // 对于每个属性值，使用反射机制获取其值，如果是字符串类型，则使用StringEscapeUtils类进行HTML编码，然后将编码后的值设置回属性中。
    // 这样就可以对返回值中的所有字符串类型的属性进行HTML编码了。
    // 注意，这种方式仅处理字符串类型的属性值，如果还有其他类型的属性需要处理，或者有其他的HTML编码需求，可以根据实际情况进行调整。

    public static <T extends Serializable> Result<T> encodeHtml(Result<T> result) throws IllegalAccessException {
        if (result == null || result.getData() == null) {
            return result;
        }

        Object data = result.getData();
        if (data instanceof IPage<?>) {
            // 如果数据是IPage类型，则对分页结果进行HTML编码
            IPage<T> page = (IPage<T>) data;
            encodeHtml(page.getRecords());
        } else if (data instanceof Collection<?>) {
            // 如果数据是集合类型，先将集合中的对象逐一处理
            Collection<T> dataList = (Collection<T>) data;
            encodeHtml(dataList);
        } else {
            // 否则，直接处理数据对象本身
            encodeHtmlForObject(data);
        }

//        if (result.getData() instanceof Collection) {
//            // 如果数据是集合类型，先将集合中的对象逐一处理
//            Collection<T> dataList = (Collection<T>) result.getData();
//            for (T data : dataList) {
//                encodeHtmlForObject(data);
//            }
//        } else {
//            // 否则，直接处理数据对象本身
//            encodeHtmlForObject(result.getData());
//        }
        return result;
    }

    /**
     * 对集合中的所有对象进行HTML编码
     * @param dataList
     * @param <T>
     * @throws IllegalAccessException
     */
    private static <T> void encodeHtml(Collection<T> dataList) throws IllegalAccessException {
        for (T data : dataList) {
            encodeHtmlForObject(data);
        }
    }

    /**
     * 对对象的所有字符串类型属性进行HTML编码
     * @param object
     * @param <T>
     * @throws IllegalAccessException
     */
    private static <T> void encodeHtmlForObject(T object) throws IllegalAccessException {
        if (object == null) {
            return;
        }
        // 获取对象的所有属性
        List<Field> fields = new ArrayList<>();
        getAllFields(object.getClass(), fields);
//        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Object fieldValue = field.get(object);
            // 如果属性值是字符串类型，对其进行HTML编码
            if (fieldValue instanceof String && !"token".equals(field.getName())) {
                String originalValue = (String) fieldValue;
                if (StringUtils.isNotEmpty(originalValue)) {
                    //注释，不知道为何报错
//                    String encodedValue = stripXSS(originalValue);
//                    field.set(object, encodedValue);
                }
            }
        }
    }

    /**
     * 获取当前类所有的属性（包含父类）
     * @param clazz
     * @param fields
     */
    public static void getAllFields(Class clazz, List<Field> fields) {
        if (clazz != null && !clazz.equals(Object.class)) {
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                fields.add(field);
            }
            getAllFields(clazz.getSuperclass(), fields);
        }
    }

    // 对对象的所有字符串类型属性进行HTML编码
//    private static <T> void encodeHtmlForObject(T object) throws IllegalAccessException {
//        if (object == null) {
//            return;
//        }
//
//        // 获取对象的所有属性
//        Field[] fields = object.getClass().getDeclaredFields();
//        for (Field field : fields) {
//            field.setAccessible(true);
//            Object fieldValue = field.get(object);
//
//            // 如果属性名是"token"，则跳过
//            if ("token".equals(field.getName())) {
//                continue;
//            }
//
//            // 如果属性值是字符串类型，对其进行HTML编码
//            if (fieldValue instanceof String) {
//                String originalValue = (String) fieldValue;
//                if (StringUtils.isNotEmpty(originalValue)) {
//                    String encodedValue = StringEscapeUtils.escapeHtml4(originalValue);
//                    field.set(object, encodedValue);
//                }
//            }
//        }
//    }

}


